﻿using Autodesk.AutoCAD.DatabaseServices.Filters;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.AutoCAD.ApplicationServices;

namespace WCAD.Kean
{
    public class SpatialFiltering
    {
        //https://www.keanw.com/2012/10/querying-for-xclip-information-inside-autocad-using-net.html
        const string filterDictName = "ACAD_FILTER";
        const string spatialName = "SPATIAL";
        [CommandMethod("DXC")]
        static public void DetectXClip()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var ed = doc.Editor;
            // Ask for an xclipped xref to be selected
            var peo =new PromptEntityOptions("\nSelect xclipped block or xref");
            peo.SetRejectMessage("Must be a block or xref.");
            peo.AddAllowedClass(typeof(BlockReference), false);
            var per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK)
                return;
            var tr = doc.TransactionManager.StartTransaction();
            using (tr)
            {
                // Open the selected BlockReference
                var br =tr.GetObject(per.ObjectId, OpenMode.ForRead) as BlockReference;
                // To save multiple codepaths with the same message
                // ("No clipping information found"), we'll use a flag to
                // see whether we've found anything
                bool found = false;
                // It should always be a block reference, but it might
                // not have an extension dictionary
                if (br != null && br.ExtensionDictionary != ObjectId.Null)
                {
                    // The extension dictionary needs to contain a nested
                    // dictionary called ACAD_FILTER
                    var extdict =tr.GetObject(br.ExtensionDictionary, OpenMode.ForRead)as DBDictionary;
                    if (extdict != null && extdict.Contains(filterDictName))
                    {
                        var fildict =tr.GetObject(extdict.GetAt(filterDictName), OpenMode.ForRead) as DBDictionary;
                        if (fildict != null)
                        {
                            // The nested dictionary should contain a
                            // SpatialFilter object called SPATIAL
                            if (fildict.Contains(spatialName))
                            {
                                var fil =tr.GetObject(fildict.GetAt(spatialName), OpenMode.ForRead) as SpatialFilter;
                                if (fil != null)
                                {
                                    // We have a SpatialFilter: print its bounds
                                    var ext = fil.GetQueryBounds();
                                    ed.WriteMessage("\nFound clip from {0} to {1}.",ext.MinPoint, ext.MaxPoint);
                                    var pts = fil.Definition.GetPoints();
                                    foreach (var pt in pts)
                                    {
                                        ed.WriteMessage("\nBoundary point at {0}", pt);
                                    }
                                    found = true;
                                }
                            }
                        }
                    }
                }
                if (!found)
                {
                    ed.WriteMessage("\nNo clipping information found.");
                }
                tr.Commit();
            }
        }
    }
}
